using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;

namespace ShouldIt.Core
{
    public static class AssertProvidersContainer
    {
        private static ICollection<IAssertProvider> providers;

        static AssertProvidersContainer()
        {
            GetExportedProviders();
            if (providers.Count == 0)
            {
                Console.WriteLine("ERROR: No assert providers found.");
            }
            else
            {
                Current = providers.First();
                if (providers.Count > 1)
                {
                	var selectedType = Current.GetType();
                    Console.WriteLine(@"WARNING: More than one assert provider found:{0}{1}{0}  Arbitrarily selecting {2} [{3}].", 
						Environment.NewLine,
						string.Join(Environment.NewLine, providers.Select(x => string.Format("  - {0} [{1}]", x.GetType().FullName, x.GetType().Assembly)).ToArray()),
						selectedType.FullName,
						selectedType.Assembly.FullName);
                }
            }
        }

        private static void GetExportedProviders()
        {
            var binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            Console.WriteLine("INFO: Looking for assert providers in {0}.", binFolder);
            try
            {
                var catalog = new DirectoryCatalog(binFolder, "ShouldIt.*.dll");
                var container = new CompositionContainer(catalog);
                providers = container.GetExportedObjects<IAssertProvider>();
            }
            catch (TypeInitializationException ex)
            {
                if (ex.InnerException is TypeLoadException)
                {
                    foreach (var detail in ((ReflectionTypeLoadException)ex.InnerException).LoaderExceptions)
                    {
                        Console.WriteLine("ERROR: Loader Exception: {0}", detail.Message);
                    }
                }
                throw;
            }
        }

        public static IAssertProvider Current { get; private set; }

        public static void SetCurrent(Type type)
        {
            Current = providers.Where(x => x.GetType() == type).FirstOrDefault();
        }

        public static void SetCurrent(IAssertProvider provider)
        {
            Current = provider;
        }
    }
}